package com.example.webdriveddd.domain;

import com.example.webdriveddd.dto.FileInfoDTO;
import com.example.webdriveddd.dto.FolderDTO;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

@Entity
@Table(uniqueConstraints = {
        @UniqueConstraint(columnNames = {"file_name","file_type","parent_file_id","user_id"})
})
public class FileInfo {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Getter
    private int id;
    @Column(name = "file_name")
    @Getter
    private String fileName;
    @Column(name = "file_type")
    private String fileType;
    @Getter
    private long fileSize;
    @Getter
    @Setter
    private String description;

    @OneToMany(mappedBy = "parentFile", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<FileInfo> subFiles = new HashSet<>();
    @ManyToOne
    @Setter
    @JoinColumn(name = "parent_file_id")
    private FileInfo parentFile;
    @ManyToMany
    private Set<FileTag> fileTags = new HashSet<>();
    @ManyToOne
    @JoinColumn(name = "user_id")
    @Getter
    private User user;

    private LocalDateTime uploadTime=LocalDateTime.now();

    @Embedded
    private ShareInfo shareInfo=ShareInfo.disable();

    protected FileInfo(){}

    public FileInfo(String fileName, String fileType, long fileSize,FileInfo parentFile, User user) {
        this.fileName = fileName;
        if (!fileType.equals("dir") && !fileType.equals("file")) {
            throw new IllegalArgumentException("file type must be dir or file");
        }
        this.fileType = fileType;
        this.fileSize = fileSize;
        this.parentFile = parentFile;
        this.user = user;
    }

    public FileInfo parentFile() {
        return parentFile;
    }

    public Set<FileInfo> subFiles() {
        return subFiles;
    }

    public Set<FileTag> tags() {
        return fileTags;
    }

    public boolean isDir() {
        return this.fileType.equals("dir");
    }

    public boolean isFile() {
        return this.fileType.equals("file");
    }

    public void share(String password){
        this.shareInfo=ShareInfo.enable(password);
    }

    public void cancelShare(){
        this.shareInfo=ShareInfo.disable();
    }

    public boolean isShare(){
        return this.shareInfo.isEnabled();
    }

    public boolean verifySharePassword(String password){
        if (!this.shareInfo.isEnabled()){
            throw new RuntimeException();
        }
        return shareInfo.verifyPassword(password);
    }

    public String getPath(){
        String filename=this.fileName;
        if(parentFile==null){
            return filename;
        }
        if(parentFile.fileName.equals("/")){
            return parentFile.fileName+filename;
        }
        return parentFile.getPath()+"/"+filename;
    }

    public FileInfo copyFileInfo(FileInfo parentFile, User user) {
        FileInfo fileInfo = new FileInfo();
        fileInfo.fileName = this.fileName;
        fileInfo.fileType = this.fileType;
        fileInfo.fileSize = this.fileSize;
        fileInfo.parentFile = parentFile;
        fileInfo.user = user;
        return fileInfo;
    }

    public boolean fileInfoEquals(FileInfo fileInfo) {
        return this.fileName.equals(fileInfo.fileName)&&this.fileType.equals(fileInfo.fileType);
    }
    public boolean equals(Object other) {
        if (other instanceof FileInfo otherFile) {
            if (otherFile == this) {
                return true;
            }
            if (otherFile.id == this.id) {
                return true;
            }
            FileInfo thisParent=this.parentFile;
            FileInfo otherParent=otherFile.parentFile;
            System.out.println(Objects.equals(thisParent,otherParent));
            if (otherFile.fileName.equals(this.fileName) && otherFile.fileType.equals(this.fileType) && Objects.equals(otherFile.parentFile,this.parentFile) && Objects.equals(otherFile.user,this.user)) {
                return true;
            }
            return false;
        }
        return false;
    }

    public int hashCode() {
        return Objects.hash(fileName, fileType,parentFile.id,user.getId());
    }

    public FileInfoDTO toDTO() {
        FileInfoDTO fileInfoDTO = new FileInfoDTO();
        fileInfoDTO.setFileName(this.fileName);
        fileInfoDTO.setFileType(this.fileType);
        fileInfoDTO.setFileSize(this.fileSize);
        fileInfoDTO.setId(this.id);
        fileInfoDTO.setParentId(this.parentFile.id);
        fileInfoDTO.setUserId(this.user.getId());
        fileInfoDTO.setShared(this.shareInfo.isEnabled());
        fileInfoDTO.setDescription(this.description);
        fileInfoDTO.setUploadTime(this.uploadTime);
        return fileInfoDTO;
    }
    public FolderDTO toFolderDTO(){
        FolderDTO folderDTO = new FolderDTO();
        folderDTO.setFolderId(this.id);
        folderDTO.setFolderName(this.fileName);
        if (this.parentFile == null) {
            folderDTO.setParentId(-1);
        }else {
            folderDTO.setParentId(this.parentFile.id);
        }
        folderDTO.setFolderPath(this.getPath());
        folderDTO.setUserId(this.user.getId());
        folderDTO.setShared(this.isShare());
        folderDTO.setDescription(this.description);
        folderDTO.setUploadTime(this.uploadTime);
        folderDTO.setSubFiles(subFiles().stream().map(FileInfo::toDTO).collect(Collectors.toSet()));
        return folderDTO;
    }
}
